package com.yiyihealth.cherriesadmin.service.impl;


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.yiyihealth.cherriesadmin.core.http.HttpResult;
import com.yiyihealth.cherriesadmin.core.utils.JKTUtil;
import com.yiyihealth.cherriesadmin.mapper.*;
import com.yiyihealth.cherriesadmin.model.*;
import com.yiyihealth.cherriesadmin.model.his.DepartmentDoctorScheduling;
import com.yiyihealth.cherriesadmin.model.his.ExecutionResult;
import com.yiyihealth.cherriesadmin.model.jkt.JThealth;
import com.yiyihealth.cherriesadmin.model.jkt.JktFunc10009;
import com.yiyihealth.cherriesadmin.service.AppointRegistrationService;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.jws.WebMethod;
import javax.jws.WebService;
import java.io.IOException;
import java.io.StringWriter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * targetNamespace：指定命名空间
 * name：portType的名称
 * portName：port的名称
 * serviceName：服务名称
 * endpointInterface：SEI接口地址，如果一个服务类实现了多个接口，只需要发布一个接口的方法，可通过此注解指定要发布服务的接口。
 * <p>
 * ---------------------
 * <p>
 * 本文来自 HryReal 的CSDN 博客 ，全文地址请点击：https://blog.csdn.net/qq_33394088/article/details/72783335?utm_source=copy
 * @author chen
 */
@Service
@WebService(serviceName = "AppointRegistrationService")
@Component
@Slf4j
public class AppointRegistrationImpl implements AppointRegistrationService {

    @Resource
    private PubPatientsMapper patientsMapper;
    @Resource
    private PubPatientExtMapper pubPatientExtMapper;
    @Resource
    private PubDictionaryMapper dictionaryMapper;
    @Resource
    private PubDepartmentsMapper departmentsMapper;
    @Resource
    private PubHospitalMapper hospitalMapper;
    @Resource
    private OrdAppointmentMapper appointmentMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedisTemplate<Object, Object> redisCacheTemplate;
    @Resource
    private OrdSourceDetailMapper sourceDetailMapper;
    @Resource
    private OrdSchedulingMapper schedulingMapper;
    @Resource
    private OrdSchedulingTemplateMapper ordSchedulingTemplateMapper;
    @Resource
    private PubSuffererMapper suffererMapper;
    @Resource
    private PubDoctorMapper doctorMapper;
    @Resource
    private PubBindInfoMapper bindInfoMapper;
    @Resource
    private JktFunc10009 jktFunc10009;
    @Resource
    private JThealth jThealth;

    @Override
    @WebMethod
    public String funMain(String XmlRequest) {
        log.info(XmlRequest);
        String XmlResponse = null;
        Document document = null;
        Document documentResult = null;
        // 将字符串转为XML
        try {
            document = DocumentHelper.parseText(XmlRequest);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //获取子节点
        Element funcodeElt = rootElt.element("funcode");
        String funcode = funcodeElt.getTextTrim();

        if (!"data".equals(rootName)) {
            documentResult = DocumentHelper.createDocument();
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("XML语法有误");
            return xmlToString(documentResult);
        }
        try {
            switch (funcode) {
                case "100101":
                    XmlResponse = interfaceStatusMonitoring(XmlRequest);
                    break;
                case "100102":
                    //3.1.1.2.复诊患者查询接口
                    XmlResponse = reviewPatientInquiryInterface(document);
                    break;
                case "100201":
                    //科室排班查询
                    XmlResponse = departmentScheduling(document);
                    break;
                case "100202":
                    //医生排班查询
                    XmlResponse = doctorScheduling(document);
                    break;
                case "100204":
                    //排班号源查询
                    XmlResponse = schedulingSourceQuery(document);
                    break;
                case "100206":
                    // 患者注册
                    XmlResponse = patientRegistration(document);
                    break;
                case "100207":
                    //患者信息修改
                    XmlResponse = patientInformationModification(document);
                    break;
                case "100208":
                    //预约挂号
                    XmlResponse = appointmentRegistration(document);
                    break;
                case "100209":
                    //取消预约
                    XmlResponse = cancelAppointment(document);
                    break;
                case "100210":
                    //号源释放
                    XmlResponse = sourceRelease(document);
                    break;
                default:
                    documentResult = DocumentHelper.createDocument();
                    Element root = documentResult.addElement("data");
                    Element stateElt = root.addElement("state");
                    stateElt.setText("-1");
                    Element resultElt = root.addElement("result");
                    resultElt.setText("XML语法有误");
                    XmlResponse = xmlToString(documentResult);
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info(XmlResponse);
        return XmlResponse;
    }


    /**
     * 接口状态监测
     *
     * @param XmlRequest
     * @return
     */
    private String interfaceStatusMonitoring(String XmlRequest) {
        Document documentResult = DocumentHelper.createDocument();
        Element root = documentResult.addElement("data");
        Element stateElt = root.addElement("state");
        stateElt.setText("0");
        Element resultElt = root.addElement("result");
        resultElt.setText("交易验证通过");
        String XmlResponse = xmlToString(documentResult);
        return XmlResponse;
    }

    /**
     * 100102 复诊患者查询接口 该接口由医院开发， 平台会调用该接口判断当前患者是否为医院的复诊患者！
     *
     * @param document
     * @return
     */
    private String reviewPatientInquiryInterface(Document document)  {

        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //获取子节点
        Element idcardtypeElt = rootElt.element("idcardtype");
        String idcardtype = idcardtypeElt.getTextTrim();
        Element idcardElt = rootElt.element("idcard");
        String idcard = idcardElt.getTextTrim();
        Map<String, Object> map = new HashMap<>(16);
        map.put("Idcard",idcard);
        List<PubPatientExt> patientExts = pubPatientExtMapper.selectList(map);
        Document documentResult = DocumentHelper.createDocument();
        Element root = documentResult.addElement("data");
        Element stateElt = root.addElement("state");
        stateElt.setText("0");
        if (!CollectionUtils.isEmpty(patientExts)) {
            Element resultElt = root.addElement("result");
            resultElt.setText("有患者就诊记录");
            Element isregElt = root.addElement("isreg");
            isregElt.setText("F");
        } else {
            root.addAttribute("result", "无患者就诊记录！");
            Element isregElt = root.addElement("isreg");
            isregElt.setText("F");
        }
        return xmlToString(documentResult);
    }

    /**
     * 100201 科室排班查询   查询医院科室当天开始至未来 7 天内的排班情况， 放号时间由医院自行控制
     * （建议参照省平台规范， 市级医院下午 14 点放号、 省直医院下午 15 点放号），
     * 未到放号时间的排班编号返回为 0， 到放号时间后返回正常医院排班编号。
     *
     * @param document
     * @return
     */
    private String departmentScheduling(Document document) throws Exception {
        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //获取子节点
        Element orgidElt = rootElt.element("orgid");
        String orgid = orgidElt.getTextTrim();
        Element deptidElt = rootElt.element("deptid");
        String deptid = deptidElt.getTextTrim();
        Map<String, Object> map = new HashMap<>(16);
        map.put("depInternalCode",deptid);
        List<PubDepartments> departments = departmentsMapper.selectList(map);
        map.clear();
        map.put("depId",departments.get(0).getId());
        map.put("doctorPracticeScope","0");
        List<OrdScheduling> schedulingList = schedulingMapper.selectList(map);
        List<DepartmentDoctorScheduling> departmentDoctorSchedulingList = new ArrayList<>();
        for (OrdScheduling scheduling : schedulingList) {
            if (LocalDate.now().equals(scheduling.getSchedulingTime())){
                continue;
            }
            DepartmentDoctorScheduling dds = generate(scheduling);
            LocalDate localDate = LocalDate.now().plusDays(-1);
            // 提前一周放号
            if (localDate.isBefore(scheduling.getSchedulingTime())){
                departmentDoctorSchedulingList.add(dds);
            }
        }
        departmentDoctorSchedulingList = departmentDoctorSchedulingList.stream().filter(departmentDoctorScheduling -> !departmentDoctorScheduling.getNumcount().equals("0")).sorted(Comparator.comparing(DepartmentDoctorScheduling::getSchid).reversed()).collect(Collectors.toList());
        Document documentResult = DocumentHelper.createDocument();
        if (departmentDoctorSchedulingList.size() > 0) {
            documentResult = generateDepartmentDoctorScheduling(departmentDoctorSchedulingList);
        } else {
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("暂未放号或者预约已过期");
        }
        System.out.println(xmlToString(documentResult));
        return xmlToString(documentResult);
    }

    /**
     * 医生排班查询
     *
     * @param document
     * @return
     */
    private String doctorScheduling(Document document) throws Exception {
        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //获取子节点
        Element orgidElt = rootElt.element("orgid");
        String orgid = orgidElt.getTextTrim();
        Element docidElt = rootElt.element("docid");
        String docidid = docidElt.getTextTrim();
        Element docName = rootElt.element("docname");
        String dName = docName.getTextTrim();
        // 工号为空且姓名不为空
        List<PubDoctor>  doctors= new ArrayList<>();
        Map<String, Object> map = new HashMap<>(16);
        if (!StrUtil.isBlank(dName)){
            map.put("doctorName",dName);
            doctors = doctorMapper.selectList(map);
        }else {
            map.put("doctorName",dName);
            map.put("doctorCode",docidid);
            doctors = doctorMapper.selectList(map);
            PubDoctor doctor = doctors.get(0);
            if (Optional.ofNullable(doctor.getDoctorPracticeDivision()).isPresent() && doctor.getDoctorPracticeDivision().equals("yiyi")){
                map.clear();
                map.put("doctorName",doctors.get(0).getDoctorName());
                doctors = doctorMapper.selectList(map);
            }
        }
        // 医生排班缓存 key=前缀+机构编码+医生内码
        List<OrdScheduling> list=new ArrayList<>();
        for (PubDoctor doctor:doctors){
            map.clear();
            map.put("doctorId",doctor.getId());
            map.put("doctorPracticeScope","0");
            list.addAll(schedulingMapper.selectList(map));
        }
        List<DepartmentDoctorScheduling> departmentDoctorSchedulingList = new ArrayList<>();
        for (OrdScheduling scheduling : list) {
            if (LocalDate.now().equals(scheduling.getSchedulingTime())){
                continue;
            }
            if (scheduling.getAppointmentAmount().toString().equals("0")) {
                continue;
            }
            DepartmentDoctorScheduling dds = generate(scheduling);
            LocalDate localDate = LocalDate.now().plusDays(-1);
            // 提前一周放号
            if (localDate.isBefore(scheduling.getSchedulingTime())){
                departmentDoctorSchedulingList.add(dds);
            }
        }
        departmentDoctorSchedulingList = departmentDoctorSchedulingList.stream().sorted(Comparator.comparing(DepartmentDoctorScheduling::getSchid).reversed()).collect(Collectors.toList());
        Document documentResult = DocumentHelper.createDocument();
        if (departmentDoctorSchedulingList.size() > 0) {
            documentResult = generateDepartmentDoctorScheduling(departmentDoctorSchedulingList);
        } else {
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("暂未放号或者预约已过期");
        }
        System.out.println(xmlToString(documentResult));
        return xmlToString(documentResult);
    }


    /**
     * 100204 查询排班的号源列表。
     *
     * @param document
     * @return
     */
    private String schedulingSourceQuery(Document document) throws Exception {
        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //获取子节点
        Element schidElt = rootElt.element("schid");
        String schid = schidElt.getTextTrim();
        Element orgidElt = rootElt.element("orgid");
        String orgid = orgidElt.getTextTrim();
        Element ampmElt = rootElt.element("ampm");
        String ampm = ampmElt.getTextTrim();

        //号源明细缓存 根据医院编码+排班id+上下午标志
        Map<String, Object> map = new HashMap<>(16);
        map.put("schedulingId",schid);
        map.put("status","0");
        List<OrdSourceDetail> list = sourceDetailMapper.selectList(map);
        List<OrdSourceDetail> sourceDetailList = new ArrayList();
        for (OrdSourceDetail sourceDetail : list) {
            //号源明细类型 0院内号源和1第三方号源(平台、官网)
            String sourceDetailKey="sourceDetail:"+sourceDetail.getDoctorId()+":"+sourceDetail.getSchedulingId();
            if ("1".equals(sourceDetail.getType()) && redisCacheTemplate.opsForSet().isMember(sourceDetailKey,sourceDetail.getId())) {
                sourceDetailList.add(sourceDetail);
            }
        }
        sourceDetailList = sourceDetailList.stream().sorted(Comparator.comparing(OrdSourceDetail::getId)).collect(Collectors.toList());
        Document documentResult = DocumentHelper.createDocument();
        if (sourceDetailList.size() > 0) {
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("0");
            Element resultElt = root.addElement("result");
            resultElt.setText("");
            Element listNode = root.addElement("list");
            for (OrdSourceDetail sourceDetail : sourceDetailList) {
                Element itemNode = listNode.addElement("item");
                //1. 号源编号 numid 32 N 号源在医院的唯一标识
                Element numid = itemNode.addElement("numid");
                numid.setText(sourceDetail.getId().toString());
                //2. 号源序号 numno 3 N
                Element numno = itemNode.addElement("numno");
                numno.setText(sourceDetail.getSerialNumber());
                //3. 号源日期 char 10 N 格式 YYYY-MM-DD
                Element numdate = itemNode.addElement("numdate");
                numdate.setText(sourceDetail.getSchedulingDate().format(DateTimeFormatter.BASIC_ISO_DATE));
                //4. 号源时间 char 8 N 格式 HH:MI
                Element numtime = itemNode.addElement("numtime");
                numtime.setText(sourceDetail.getVisitTime().toString());
                //5. 号源状态 numstate 2 N 0-正常 1-未放号
                Element numstate = itemNode.addElement("numstate");
                numstate.setText(sourceDetail.getStatus());
            }
        } else {
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("暂未放号或者预约已过期!");
        }
        return xmlToString(documentResult);
    }


    /**
     * 患者第一次预约某医院的号源时， 平台会将用户信息注册到医院， 医院需要
     * 保存用户在平台的编号
     *
     * @param document
     * @return
     */
    private String patientRegistration(Document document) {
        PubPatientExt patientExt = new PubPatientExt();
        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //获取子节点
        //1. 患者编号 patid 18 N 患者在平台的唯一标识
        Element patidElt = rootElt.element("patid");
        String platFromId = patidElt.getTextTrim();
        patientExt.setPatNo(platFromId);
        //5. 证件号码 idcard 20 N
        Element idcardElt = rootElt.element("idcard");
        String idcard = idcardElt.getTextTrim();
        patientExt.setIdcard(idcard);
        Map<String, Object> map = new HashMap<>(16);
        map.put("patNo",platFromId);
        List<PubPatientExt> patientExtList = pubPatientExtMapper.selectList(map);
        if (!CollectionUtils.isEmpty(patientExtList)){
            PubPatientExt pubPatientExt = patientExtList.get(0);
            Document documentResult = DocumentHelper.createDocument();
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("0");
            Element resultElt = root.addElement("result");
            resultElt.setText("注册患者信息成功");
            Element patientElt = root.addElement("patientid");
            patientElt.setText(pubPatientExt.getId().toString());
            return xmlToString(documentResult);
        }
        //2. 患者姓名 patname 20 N
        Element patnameElt = rootElt.element("patname");
        String patname = patnameElt.getTextTrim();
        patientExt.setPatName(patname);
        //3. 患者性别 patsex 1 N 见 S101-01 性别代 码
        Element patsexElt = rootElt.element("patsex");
        String patsex = patsexElt.getTextTrim();
        patientExt.setPatSex(patsex);
        //4. 证件类型 idcardtype 1 N 见证件类型代码
        Element idcardtypeElt = rootElt.element("idcardtype");
        String idcardtype = idcardtypeElt.getTextTrim();
        patientExt.setIdcardType(idcardtype);
        //5. 证件号码 idcard 20 N
        patientExt.setIdcard(idcard);
        //6. 医保卡类型 medcardtype 1 Y 见医保卡类型代码
        Element medcardtypeElt = rootElt.element("medcardtype");
        patientExt.setMedcardType(medcardtypeElt.getTextTrim());
        //7. 医保卡号 medcardno 20 Y
        Element medcardnoElt = rootElt.element("medcardno");
        String medcardno = medcardnoElt.getTextTrim();
        patientExt.setMobileNo(medcardno);
        //8. 手机号码 mobileno 11 N
        Element mobilenoElt = rootElt.element("mobileno");
        String mobileno = mobilenoElt.getTextTrim();
        patientExt.setMobileNo(mobileno);
        //9. 联系地址 address 255 Y
        Element addressElt = rootElt.element("address");
        String address = addressElt.getTextTrim();
        patientExt.setAddress(address);
        pubPatientExtMapper.insert(patientExt);
        map.clear();
        map.put("patIdentityNum",patientExt.getIdcard());
        PubPatients patients = patientsMapper.selectByIDCard(patientExt.getMobileNo());
        if (!Optional.ofNullable(patients).isPresent()){
            patients.setPatName(patientExt.getPatName());
            patients.setPatCertifiNum(patientExt.getIdcard());
            if (IdcardUtil.isValidCard(patientExt.getIdcard())){
                patients.setPatIdentityNum(patientExt.getIdcard());
                patients.setPatBirthday(LocalDateTimeUtil.of(IdcardUtil.getBirthDate(patientExt.getIdcard())));
            }
            patients.setPatPhone(patientExt.getMobileNo());
            patients.setPatFamAddress(patientExt.getAddress());
            patients.setPatSex(IdcardUtil.getGenderByIdCard(patientExt.getIdcard()));
            patientsMapper.insert(patients);
            patients.setPatCardNum(patients.getId().toString());
            patientsMapper.updateByPrimaryKeySelective(patients);
            PubSufferer pubSufferer = new PubSufferer();
            pubSufferer.setPatIdentityNum(patients.getPatIdentityNum());
            pubSufferer.setPatId(patients.getId());
            pubSufferer.setPatName(patients.getPatName());
            pubSufferer.setPatSex(patients.getPatSex());
            pubSufferer.setPatPhone(patients.getPatPhone());
            suffererMapper.insert(pubSufferer);
        }
        Document documentResult = DocumentHelper.createDocument();
        Element root = documentResult.addElement("data");
        Element stateElt = root.addElement("state");
        stateElt.setText("0");
        Element resultElt = root.addElement("result");
        resultElt.setText("注册患者信息成功");
        Element patientElt = root.addElement("patientid");
        patientElt.setText(patientExt.getId().toString());
        return xmlToString(documentResult);
    }

    /**
     * 患者信息修改
     *
     * @param document
     * @return
     */
    private String patientInformationModification(Document document) {
        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //获取子节点
        String XmlResponse = "交易验证信息成功！";
        //1. 患者编号 patid 18 N 患者在平台的唯一标识
        Element patidElt = rootElt.element("patid");
        String platFromId = patidElt.getTextTrim();
        Map<String, Object> map = new HashMap<>(16);
        map.put("PatId",platFromId);
        PubPatientExt patients = pubPatientExtMapper.selectList(map).get(0);
        if (patients == null) {
            Document documentResult = DocumentHelper.createDocument();
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("未查询到患者注册信息");
            return xmlToString(documentResult);
        }
        //2. 患者姓名 patname 20 N
        Element patnameElt = rootElt.element("patname");
        String patname = patnameElt.getTextTrim();
        patients.setPatName(patname);
        //3. 患者性别 patsex 1 N 见 S101-01 性别代 码
        Element patsexElt = rootElt.element("patsex");
        String patsex = patsexElt.getTextTrim();
        patients.setPatSex(patsex);
        //6. 医保卡类型 medcardtype 1 Y 见医保卡类型代码
        Element medcardtypeElt = rootElt.element("medcardtype");
        String medcardtype = medcardtypeElt.getTextTrim();
        patients.setMedcardType(medcardtype);
        //7. 医保卡号 medcardno 20 Y
        Element medcardnoElt = rootElt.element("medcardno");
        String medcardno = medcardnoElt.getTextTrim();
        patients.setMedcardNo(medcardno);
        //8. 手机号码 mobileno 11 N
        Element mobilenoElt = rootElt.element("mobileno");
        String mobileno = mobilenoElt.getTextTrim();
        patients.setMobileNo(mobileno);
        //9. 联系地址 address 255 Y
        Element addressElt = rootElt.element("address");
        if(addressElt != null){
            String address = addressElt.getTextTrim();
            patients.setAddress(address);
        }

        pubPatientExtMapper.updateByPrimaryKeySelective(patients);

        Document documentResult = DocumentHelper.createDocument();
        Element root = documentResult.addElement("data");
        Element stateElt = root.addElement("state");
        stateElt.setText("0");
        Element resultElt = root.addElement("result");
        resultElt.setText("修改患者信息成功");
        return xmlToString(documentResult);
    }

    /**
     * 号源释放功能说明
     * 当患者通过省平台进行退号时， 省平台将调用该接口将退号信息传给医院，
     * 地上平台处理退号信息后， 返回退号结果。
     * 当天号源直接取消预约时间为号源时间前半个小时， 其他号源截至取消预约
     * 时间为就诊前一天 24 时。
     * 为防止黄牛退号再挂号， 此处取消预约后医院号源设置为锁定状态， 平台会
     * 随机一个时间点(1-2 小时)内调用医院号源释放接口， 此时医院将号源从锁定状
     * 态更新为可预约。
     *
     * @param document
     * @return
     */
    private String sourceRelease(Document document) throws Exception {
        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //获取子节点
        //1. 号源日期 numdate 8 N 格式 YYYYMMDD
        Element numdateElt = rootElt.element("numdate");
        String numdate = numdateElt.getTextTrim();
        //2. 号源编号 numid 32 N
        Element numidElt = rootElt.element("numid");
        String numid = numidElt.getTextTrim();
        //3. 排班编号 schid 32 N
        Element schidElt = rootElt.element("schid");
        String schid = schidElt.getTextTrim();
        //4. 上下午标志 ampm 2 N 1-上午 2-下午
        Element ampmElt = rootElt.element("ampm");
        String ampm = ampmElt.getTextTrim();
        //5. 号源序号 numno 3 N
        Element numnoElt = rootElt.element("numno");
        String numno = numnoElt.getTextTrim();

        //释放号源从已消耗 变为待预约
        OrdScheduling scheduling =schedulingMapper.selectByPrimaryKey(Long.valueOf(schid));
        OrdSourceDetail sourceDetail =sourceDetailMapper.selectByPrimaryKey(Long.valueOf(numid));
        String sourceDetailKey="sourceDetail:"+scheduling.getDoctorId()+":"+scheduling.getId();
        String schedulingKey="scheduling:"+scheduling.getDoctorId()+":"+scheduling.getId();
        stringRedisTemplate.opsForValue().increment(schedulingKey,1);
        stringRedisTemplate.opsForSet().add(sourceDetailKey,numid.trim());
        Document documentResult = DocumentHelper.createDocument();
        Element root = documentResult.addElement("data");
        Element stateElt = root.addElement("state");
        stateElt.setText("0");
        Element resultElt = root.addElement("result");
        resultElt.setText("释放号源成功");
        JKTUtil.jktFunc10009Sou(jktFunc10009,jThealth,sourceDetail);
        return xmlToString(documentResult);
    }

    /**
     * 取消预约: 功能说明
     * 当患者通过省平台进行退号时， 省平台将调用该接口将退号信息传给医院，
     * 地上平台处理退号信息后， 返回退号结果。
     * 当天号源直接取消预约时间为号源时间前半个小时， 其他号源截至取消预约
     * 时间为就诊前一天 24 时。
     * 为防止黄牛退号再挂号， 此处取消预约后医院号源设置为锁定状态， 平台会
     * 随机一个时间点(1-2 小时)内调用医院号源释放接口， 此时医院将号源从锁定状
     * 态更新为可预约
     *
     * @param document
     * @return
     */

    private String cancelAppointment(Document document) throws Exception {
        String XmlResponse = "交易验证信息成功！";
        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        //1. 医院编号 orgid 20 N医院在平台的唯一编号
        Element orgidElt = rootElt.element("orgid");
        String orgid = orgidElt.getTextTrim();
        //1. 预约编号 regid 18 N 本次预约在平台的浙江省医院预约诊疗服务平台医院接入规范 web service（V1.0.3）唯一标识
        Element regidElt = rootElt.element("regid");
        String regid = regidElt.getTextTrim();
        //5. 服务商编号 spid 6 N
        Element spidElt = rootElt.element("spid");
        String spid = spidElt.getTextTrim();
        //6. 服务商名称 spname 20 N
//        Element spnameElt = rootElt.element("spname");
//        String spname = spnameElt.getTextTrim();
        //7. 操作员 oper 20 N 工号或 IP
        Element operElt = rootElt.element("oper");
        String oper = operElt.getTextTrim();
        OrdAppointment appointment = appointmentMapper.selectByAppId(Long.valueOf(regid));
        Document documentResult = DocumentHelper.createDocument();
        if (appointment != null) {
            ExecutionResult executionResult = deleteDataHIS(appointment);
            if (!executionResult.getOutResult().equals(0)){
                Element root = documentResult.addElement("data");
                Element stateElt = root.addElement("state");
                stateElt.setText("-1");
                Element resultElt = root.addElement("result");
                resultElt.setText("未找到预约记录或者已取消预约");
                return xmlToString(documentResult);
            }
            //预约状态(0已预约 1已过期 2已取号 3患者取消 4医院取消)
            appointment.setAppStatus(3);
            appointment.setSpNo(spid);
            appointment.setCancelDate(LocalDateTime.now());
            appointmentMapper.updateByPrimaryKeySelective(appointment);
            OrdSourceDetail sourceDetail = sourceDetailMapper.selectByPrimaryKey(appointment.getSourceDetailId());
            //号源释放
            sourceDetail.setId(appointment.getSourceDetailId());
            sourceDetail.setStatus("0");
            //使用状态(1窗口挂号 2平台预约取号 3平台爽约 4院内预约取号 5院内爽约 6退号 7医生停诊)
            sourceDetail.setState("6");
            sourceDetailMapper.updateByPrimaryKeySelective(sourceDetail);
            OrdScheduling scheduling = schedulingMapper.selectByPrimaryKey(appointment.getSchedulingId());
            //因为在同步情况下，所以就直接加一
            scheduling.setAmountCurrent(Optional.ofNullable(scheduling.getAmountCurrent()).orElse(0) + 1);
            schedulingMapper.updateByPrimaryKeySelective(scheduling);

            //不释放号源 由平台统一释放号源
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("0");
            Element resultElt = root.addElement("result");
            resultElt.setText("取消预约信息成功！ ");
        } else {
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("未找到预约记录或者已取消预约");
        }
        return xmlToString(documentResult);
    }

    /**
     * 当患者通过省平台进行预约挂号时， 省平台根据全省统一的业务规范进行验
     * 证， 如果当前预约符合现有规则那么省平台调用该接口将挂号信息传给医院进行
     * 挂号处理， 并返回挂号结果， 医院需要保存好取号密码， 退号时使用
     *
     * @param document
     * @return
     */
    private String appointmentRegistration(Document document) throws Exception {
        String XmlResponse = "交易验证信息成功！";
        //获取根节点
        Element rootElt = document.getRootElement();
        //获取根节点名称
        String rootName = rootElt.getName();
        Map<String, Object> map = new HashMap<>(16);
        Document documentResult = DocumentHelper.createDocument();

        //1. 预约编号 regid 18 N 本次预约在平台的浙江省医院预约诊疗服务平台医院接入规范 web service（V1.0.3）唯一标识
        Element regidElt = rootElt.element("regid");
        String regid = regidElt.getTextTrim();
        Element visitdateElt = rootElt.element("visitdate");
        String visitdate = visitdateElt.getTextTrim();
        String platFromId = rootElt.element("patid").getTextTrim();
        PubPatientExt pubPatientExt = pubPatientExtMapper.selectByPlatFromId(platFromId);
        PubPatients patients = patientsMapper.selectByIDCard(pubPatientExt.getMobileNo());
        PubSufferer pubSufferer = new PubSufferer();
        if (Optional.ofNullable(pubPatientExt).isPresent()){
            if (Optional.ofNullable(patients).isPresent()){
                patients.setPatName(pubPatientExt.getPatName());
                patients.setPatIdentityNum(pubPatientExt.getIdcard());
                patients.setPatSex(IdcardUtil.getGenderByIdCard(pubPatientExt.getIdcard()));
                patients.setPatPhone(pubPatientExt.getMobileNo());
                patients.setPassword(pubPatientExt.getMobileNo());
                patientsMapper.updateByPrimaryKeySelective(patients);
                map.put("patId",patients.getId());
                map.put("patIdentityNum",patients.getPatIdentityNum());
                List<PubSufferer> suffererList = suffererMapper.selectList(map);
                if (CollectionUtils.isEmpty(suffererList)){
                    pubSufferer = new PubSufferer();
                    pubSufferer.setPatIdentityNum(patients.getPatIdentityNum());
                    pubSufferer.setPatId(patients.getId());
                    pubSufferer.setPatName(patients.getPatName());
                    pubSufferer.setPatSex(patients.getPatSex());
                    pubSufferer.setPatPhone(patients.getPatPhone());
                    suffererMapper.insert(pubSufferer);
                }else {
                    pubSufferer = suffererList.get(0);
                    pubSufferer.setPatIdentityNum(patients.getPatIdentityNum());
                    pubSufferer.setPatId(patients.getId());
                    pubSufferer.setPatName(patients.getPatName());
                    pubSufferer.setPatSex(patients.getPatSex());
                    pubSufferer.setPatPhone(patients.getPatPhone());
                    suffererMapper.updateByPrimaryKeySelective(pubSufferer);
                }
            }else {
                patients = new PubPatients();
                patients.setPatName(pubPatientExt.getPatName());
                patients.setPatIdentityNum(pubPatientExt.getIdcard());
                patients.setPatSex(IdcardUtil.getGenderByIdCard(pubPatientExt.getIdcard()));
                patients.setPatPhone(pubPatientExt.getMobileNo());
                patients.setPassword(pubPatientExt.getMobileNo());
                patientsMapper.insert(patients);
                pubSufferer = new PubSufferer();
                pubSufferer.setPatIdentityNum(patients.getPatIdentityNum());
                pubSufferer.setPatId(patients.getId());
                pubSufferer.setPatName(patients.getPatName());
                pubSufferer.setPatSex(patients.getPatSex());
                pubSufferer.setPatPhone(patients.getPatPhone());
                suffererMapper.insert(pubSufferer);
            }
        }else {
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("用户信息不存在,请先注册！");
            return xmlToString(documentResult);
        }
        //2. 号源编号 numid 32 N 号源在医院的唯一 标识
        Element numidElt = rootElt.element("numid");
        String numid = numidElt.getTextTrim();
        map.clear();
        map.put("schedulingId",rootElt.element("schid").getTextTrim());
        //预约状态(0已预约 1已过期 2已取号 3患者取消 4院内取消)
        map.put("serialNumber",numid);
        OrdSourceDetail sourceDetail = sourceDetailMapper.selectByPrimaryKey(Long.valueOf(numid));
        if (!Optional.ofNullable(sourceDetail).isPresent()){
            Element root = documentResult.addElement("data");
            Element stateElt = root.addElement("state");
            stateElt.setText("0");
            Element resultElt = root.addElement("result");
            String text = sourceDetail.getDepName()+sourceDetail.getDoctorName()+"医生"+sourceDetail.getBinName()+"第"+sourceDetail.getSerialNumber()+"号已被预约！";
            resultElt.setText(text);
            return xmlToString(documentResult);
        }
        //同一个患者同一个排班不能预约两个号子
        HashMap<String, Object> paramMap = new HashMap<>();
        paramMap.put("sourceDetailId",sourceDetail.getId());
        paramMap.put("appStatus","0");
        List<OrdAppointment> appointmentList = appointmentMapper.selectList(paramMap);
        if (!CollectionUtils.isEmpty(appointmentList)){

            Element root = documentResult.getRootElement();
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("此号已被预约 请选择其他号源！");
            return xmlToString(documentResult);
        }
        paramMap.clear();
        paramMap.put("schedulingId",sourceDetail.getSchedulingId());
        paramMap.put("patId",pubSufferer.getId());
        paramMap.put("appStatus","0");
        //同一个患者同一个排班下 只能预约一个号子
        appointmentList = appointmentMapper.selectList(paramMap);
        if (!CollectionUtils.isEmpty(appointmentList)){
            OrdAppointment ordAppointmentT = appointmentList.get(0);
            Element root = documentResult.getRootElement();
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("您已经预约"
                    +ordAppointmentT.getDepName()
                    +ordAppointmentT.getDoctorName()
                    +LocalDateTimeUtil.format(ordAppointmentT.getVisitDate(),DatePattern.CHINESE_DATE_PATTERN)
                    +ordAppointmentT.getVisitTime()+",第"+ordAppointmentT.getSerialNumber()+"号，请勿重复预约");
            return xmlToString(documentResult);
        }

        paramMap.clear();
        paramMap.put("schedulingId",sourceDetail.getSchedulingId());
        paramMap.put("patIdentityNum",pubSufferer.getPatIdentityNum());
        paramMap.put("appStatus","0");
        //同一个患者同一个排班下 只能预约一个号子
        appointmentList = appointmentMapper.selectList(paramMap);
        if (!CollectionUtils.isEmpty(appointmentList)){
            OrdAppointment ordAppointmentT = appointmentList.get(0);
            Element root = documentResult.getRootElement();
            Element stateElt = root.addElement("state");
            stateElt.setText("-1");
            Element resultElt = root.addElement("result");
            resultElt.setText("您已经预约"
                    +ordAppointmentT.getDepName()
                    +ordAppointmentT.getDoctorName()
                    +LocalDateTimeUtil.format(ordAppointmentT.getVisitDate(),DatePattern.CHINESE_DATE_PATTERN)
                    +ordAppointmentT.getVisitTime()+",第"+ordAppointmentT.getSerialNumber()+"号，请勿重复预约");
            return xmlToString(documentResult);
        }

        //预约状态(0已预约 1已过期 2已取号 3患者取消 4院内取消)
        OrdAppointment ordAppointment = new OrdAppointment();
        ordAppointment.setSourceDetailId(Long.valueOf(numid));
        ordAppointment.setAppId(Long.valueOf(regid));
        //3. 患者编号 patid 18 N 患者在平台的唯一 标识
        Element patidElt = rootElt.element("patid");
        String patid = patidElt.getTextTrim();
        ordAppointment.setPatId(patients.getId());
        //官网预约渠道 非官网预约 平台唯一号与预约号不等
        ordAppointment.setAppStatus(0);
        ordAppointment.setAppType("0");
        //4. 医院编号 orgid 20 N 医院在平台的唯一 编号
        Element orgidElt = rootElt.element("orgid");
        String orgid = orgidElt.getTextTrim();
        //5. 就诊日期 visitdate 8 N YYYYMMDD
        CharSequence text = visitdate.replace("-","");
        LocalDate localDate = LocalDate.parse(text, DateTimeFormatter.BASIC_ISO_DATE);
        ordAppointment.setVisitDate(localDate);
        //6. 上下午标志 ampm 1 N 1-上午 2-下午
        Element ampmElt = rootElt.element("ampm");
        String ampm = ampmElt.getTextTrim();
        ordAppointment.setTimeState(Integer.valueOf(ampm));
        //7. 排班编号 schid 20 N 排班在医院内的唯 一标识
        Element schidElt = rootElt.element("schid");
        String schid = schidElt.getTextTrim();
        ordAppointment.setSchedulingId(Long.valueOf(schid));
        //8. 取号密码 pass 8 N 本次预约的区号密 码 7 天内唯一
        Element passElt = rootElt.element("pass");
        String pass = passElt.getTextTrim();
        ordAppointment.setPassword(pass);
        //9. 预约序号 no 3 N
        Element noElt = rootElt.element("no");
        String no = noElt.getTextTrim();

        //10. 服务商编号 spid 6 N、
        Element spidElt = rootElt.element("spid");
        String spid = spidElt.getTextTrim();
        ordAppointment.setSpNo(spid);
        //11. 服务商名称 spname 20 N
        Element spnameElt = rootElt.element("spname");
        String spname = spnameElt.getTextTrim();
        ordAppointment.setSpName(spname);

        OrdScheduling scheduling =schedulingMapper.selectByPrimaryKey(Long.valueOf(schid));
        String sourceDetailKey="sourceDetail:"+scheduling.getDoctorId()+":"+scheduling.getId();
        String schedulingKey="scheduling:"+scheduling.getDoctorId()+":"+scheduling.getId();
        synchronized (this) {
            Long value = Long.valueOf(numid);
            if (redisCacheTemplate.opsForSet().isMember(sourceDetailKey,sourceDetail.getId())) {
                //从号源列表中移除此条记录
                redisCacheTemplate.opsForValue().decrement(schedulingKey,1);
                redisCacheTemplate.opsForSet().remove(sourceDetailKey,numid);
                DepartmentDoctorScheduling departmentDoctorScheduling = generate(scheduling);
                Long appointmentId;
                appointmentId = saveAppoitment(pubSufferer,ordAppointment, sourceDetail, departmentDoctorScheduling);
                ExecutionResult executionResult =  pushDataHIS(ordAppointment);
                if (!executionResult.getOutResult().equals(0)){
                    Element root = documentResult.getRootElement();
                    Element stateElt = root.addElement("state");
                    stateElt.setText("-1");
                    Element resultElt = root.addElement("result");
                    resultElt.setText("医院端数据存储失败请重试！");
                    return xmlToString(documentResult);
                }
                if (appointmentId != null) {
                    Element root = documentResult.addElement("data");
                    Element stateElt = root.addElement("state");
                    stateElt.setText("0");
                    Element resultElt = root.addElement("result");
                    resultElt.setText("预约成功");
                    Element orderidElt = root.addElement("orderid");
                    orderidElt.setText(appointmentId.toString());
                    JKTUtil.jktFunc10009App(jktFunc10009,jThealth,ordAppointment);
                } else {
                    Element root = documentResult.getRootElement();
                    Element stateElt = root.addElement("state");
                    stateElt.setText("-1");
                    Element resultElt = root.addElement("result");
                    resultElt.setText("医院端数据存储失败请重试！");
                }
            } else if (false) {
                Element root = documentResult.addElement("data");
                Element stateElt = root.addElement("state");
                stateElt.setText("-1");
                Element resultElt = root.addElement("result");
                resultElt.setText("医院已经停诊或者已预约！");
            } else {
                Element root = documentResult.addElement("data");
                Element stateElt = root.addElement("state");
                stateElt.setText("-1");
                Element resultElt = root.addElement("result");
                resultElt.setText("号源已被预约！");
            }
        }
        return xmlToString(documentResult);
    }

    public Long saveAppoitment(PubSufferer sufferer, OrdAppointment appointment, OrdSourceDetail sourceDetail, DepartmentDoctorScheduling departmentDoctorScheduling) throws Exception {
        appointment.setDepId(sourceDetail.getDepId());
        appointment.setDepName(sourceDetail.getDepName());
        appointment.setDoctorId(sourceDetail.getDoctorId());
        appointment.setDoctorName(sourceDetail.getDoctorName());
        appointment.setBinId(sourceDetail.getBinId());
        appointment.setBinName(sourceDetail.getBinName());
        appointment.setPatId(sufferer.getId());
        appointment.setSufferId(sufferer.getPatId());
        appointment.setPatCardNum(sufferer.getPatCardNum());
        appointment.setPatName(sufferer.getPatName());
        appointment.setPatSex(sufferer.getPatSex().toString());
        appointment.setPhone(sufferer.getPatPhone());
        appointment.setPatIdentityNum(sufferer.getPatIdentityNum());
        appointment.setSerialNumber(sourceDetail.getSerialNumber());
        appointment.setSerialNumber(sourceDetail.getSerialNumber());
        appointment.setVisitTime(sourceDetail.getVisitTime());
        appointment.setCreateDate(LocalDate.now());
        appointment.setHospitalId(sourceDetail.getHospitalId());
        //预约状态(0已预约 1已过期 2已取号 3患者取消 4医生停诊 5后台取消)
        appointment.setAppStatus(0);
        appointment.setTakeCode("1");
        appointment.setCardType("1");
        appointment.setSpName("12580");
        appointmentMapper.insert(appointment);

        // 更新号源表状态，锁定号源
        sourceDetail.setStatus("1");
        //使用状态(1窗口挂号 2平台预约取号 3平台爽约 4院内预约取号 5院内爽约 6退号 7医生停诊)
        sourceDetail.setState("2");
        sourceDetailMapper.updateByPrimaryKeySelective(sourceDetail);

        OrdScheduling scheduling = schedulingMapper.selectByPrimaryKey(appointment.getSchedulingId());
        //因为在同步情况下，所以就直接加一
        scheduling.setAmountCurrent(Optional.ofNullable(scheduling.getAmountCurrent()).orElse(0) + 1);
        schedulingMapper.updateByPrimaryKeySelective(scheduling);
        return appointment.getId();
    }


    /**
     * xml转string
     *
     * @param document
     * @return
     */
    private static String xmlToString(Document document) {
        StringWriter sw = new StringWriter();
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("utf-8");
        try {
            XMLWriter xmlWriter = new XMLWriter(sw, format);
            xmlWriter.write(document);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                sw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sw.toString();
    }

    /**
     * string转xml
     *
     * @param xmlRequest
     * @return
     */
    private static Document stringToXml(String xmlRequest) {
        Document document = null;
        try {
            document = DocumentHelper.parseText(xmlRequest);
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return document;
    }

    private  Document generateDepartmentDoctorScheduling(List<DepartmentDoctorScheduling> departmentDoctorSchedulingList)  {

        departmentDoctorSchedulingList = departmentDoctorSchedulingList.stream().sorted(Comparator.comparing(DepartmentDoctorScheduling::getSchid)).collect(Collectors.toList());

        Document documentResult = DocumentHelper.createDocument();
        Element root = documentResult.addElement("data");
        root.addAttribute("state", "0");
        root.addAttribute("result", "交易验证通过！");
        Element listNode = root.addElement("list");

        for (DepartmentDoctorScheduling depDocSch : departmentDoctorSchedulingList) {
//            numcount 号源数为 0 不要返回上述参数 详见附件
            if ("0".equals(depDocSch.getNumcount())){
                continue;
            }
            Element itemNode = listNode.addElement("item");
            Element schid = itemNode.addElement("schid");
            schid.setText(depDocSch.getSchid());

            Element orgid = itemNode.addElement("orgid");
            orgid.setText(depDocSch.getOrgid());


            Element docid = itemNode.addElement("docid");
            docid.setText(depDocSch.getDocid());


            Element docname = itemNode.addElement("docname");
            docname.setText(depDocSch.getDocname());


            Element docsex = itemNode.addElement("docsex");
            // 9为未知,可以修改
            docsex.setText(Optional.ofNullable(depDocSch.getDocsex()).orElse("9"));


            Element title = itemNode.addElement("title");
            title.setText(depDocSch.getTitle());


            Element deptid = itemNode.addElement("deptid");
            deptid.setText(depDocSch.getDepId());


            Element deptname = itemNode.addElement("deptname");
            deptname.setText(depDocSch.getDeptname());


            Element schdate = itemNode.addElement("schdate");
            schdate.setText(depDocSch.getSchdate());

            Element ampm = itemNode.addElement("ampm");
            // 晚上设置为下午
            if(depDocSch.getAmpm().equals("3")){
                ampm.setText("2");
            }else{
                ampm.setText(depDocSch.getAmpm());
            }


            Element numcount = itemNode.addElement("numcount");
            numcount.setText(depDocSch.getNumcount());

            String numCount = depDocSch.getNumremain();

            Element numremain = itemNode.addElement("numremain");
//            Map<String, Object> map = new HashMap<>(16);
//            map.put("schedulingId",depDocSch.getSchid());
//            map.put("type","1");
//            List<OrdSourceDetail> sourceDetails = sourceDetailMapper.selectList(map);
            numremain.setText(depDocSch.getNumremain());

            Element categor = itemNode.addElement("categor");
            categor.setText(depDocSch.getCategor());

            Element regfee = itemNode.addElement("regfee");
            regfee.setText(depDocSch.getRegfee());

            Element fee = itemNode.addElement("fee");
            fee.setText(depDocSch.getFee());

            Element schstate = itemNode.addElement("schstate");
            schstate.setText(depDocSch.getSchstate());
        }
        return documentResult;
    }

    private DepartmentDoctorScheduling generate(OrdScheduling scheduling) throws Exception {
        /**
         * 1. 排班编号 schid 20 N 排班在医院的唯一标识浙江省医院预约诊疗服务平台医院接入规范 web service（V1.0.3）
         */
        PubHospital hospital = hospitalMapper.selectByPrimaryKey(scheduling.getHospitalId());
        PubDoctor doctor = doctorMapper.selectByPrimaryKey(scheduling.getDoctorId());
        DepartmentDoctorScheduling departmentDoctorScheduling = new DepartmentDoctorScheduling();
        departmentDoctorScheduling.setSchid(scheduling.getId().toString());
        departmentDoctorScheduling.setOrgid(hospital.getHosMarkCode().trim());
        departmentDoctorScheduling.setDocid(doctor.getDoctorCode());
        departmentDoctorScheduling.setDocname(scheduling.getDoctorName());
        //5. 医生性别 docsex 2 N 男或女
        Map<String,Object> map =new HashMap<>(2);
        map.put("","");
        departmentDoctorScheduling.setDocsex(doctor.getDoctorSex());
        //6. 医生职称 title 3 N 见专业技术职务代码
        PubDictionary dictionary = dictionaryMapper.selectByPrimaryKey(doctor.getDoctorProfessional());
        departmentDoctorScheduling.setTitle(dictionary.getDicCode());
        PubDepartments departments = departmentsMapper.selectByPrimaryKey(scheduling.getDepId());
        departmentDoctorScheduling.setDepId(departments.getDepInternalCode());
        departmentDoctorScheduling.setDeptname(scheduling.getDepName());
        departmentDoctorScheduling.setSchdate(scheduling.getSchedulingTime().format(DateTimeFormatter.BASIC_ISO_DATE));
        //10. 上下午标志 ampm 1 N 1-上午 2-下午
        departmentDoctorScheduling.setAmpm(scheduling.getTimeState().toString());


        map.clear();
        map.put("schedulingId",scheduling.getId());
        map.put("type","1");
        List<OrdSourceDetail> list = sourceDetailMapper.selectList(map);
        //11. 号源总数 numcount 3 N
        departmentDoctorScheduling.setNumcount(list.size()+"");
        List<OrdSourceDetail> sourceDetailList = new ArrayList();
        for (OrdSourceDetail sourceDetail : list) {
            //号源明细类型 0院内号源和1第三方号源(平台、官网)
            String sourceDetailKey="sourceDetail:"+sourceDetail.getDoctorId()+":"+sourceDetail.getSchedulingId();
            if ("0".equals(sourceDetail.getStatus()) && redisCacheTemplate.opsForSet().isMember(sourceDetailKey,sourceDetail.getId())) {
                sourceDetailList.add(sourceDetail);
            }
        }
        //12. 可预约数 numremain 3 N 剩余可预约的号源数量
        if (scheduling.getStatus().equals("1")){
            departmentDoctorScheduling.setNumremain(scheduling.getAppointmentAmount().toString());
        }else {
            departmentDoctorScheduling.setNumremain(sourceDetailList.size()+"");
        }

        //挂号类别 categor 1 N 1-普通 2-专家
        departmentDoctorScheduling.setCategor("2");
        PubBindInfo bindInfo = bindInfoMapper.selectByPrimaryKey(scheduling.getBinId());
        //14. 挂号费 regfee 5 N 单位元
        departmentDoctorScheduling.setRegfee(bindInfo.getGhf()==null?"0":bindInfo.getGhf().toString());
        //15. 诊疗费（诊查费） fee 5 N 单位元
        if (Optional.ofNullable(scheduling.getRegistrationFee()).isPresent()&& scheduling.getRegistrationFee().equals("1")){
            departmentDoctorScheduling.setFee("0");
        }else {
            departmentDoctorScheduling.setFee((bindInfo.getZlf()==null?"0":bindInfo.getZlf().toString()));
        }
        //16. 排班状态 schstate 2 N 0-正常 1-停诊
        departmentDoctorScheduling.setSchstate(scheduling.getStatus().equals("0")?"0":"1");
        return departmentDoctorScheduling;
    }

    /**
     * HIS预约
     * @param record
     * @return
     * @throws Exception
     */
    private ExecutionResult pushDataHIS(OrdAppointment record) throws Exception {
        //推送预约数据到HIS 86000000|20201220|0224|98603471|1|py|127.0.0.1|057170|孙泰和凤起馆|2020-12-20 09:45:50
        PubHospital hospital = hospitalMapper.selectByPrimaryKey(record.getHospitalId());
        StringBuilder inData =  new StringBuilder();
        //8650696|20181028|0|D95|76183837|2|9903|125.120.179.18|null|null|2018-10-21 17:26:40
        //用户编号 varchar2/10 用户在平台的 ID，患者注册到医院时又平台传给医院
        inData.append(record.getPatId()+"|");
        //就诊日期 Char/8 格式：YYYYMMDD 否
        inData.append(LocalDateTimeUtil.format(record.getVisitDate(), DatePattern.PURE_DATE_PATTERN)+"|");
        //上午/下午 Char/1 0-上午 ；1-下午 否
        inData.append(record.getTimeState().equals(1)?"0":"1").append("|");
        //排班 ID Char/10 用户预约的排班在医院 HIS 系统的排班ID
        OrdScheduling ordScheduling = schedulingMapper.selectByPrimaryKey(record.getSchedulingId());
        inData.append(ordScheduling.getOriginalSchedule()).append("|");
        //取号密码 char/8 8 位的取号密码，一周内不可重复，可 0开头，不可字母。
        inData.append(record.getPassword() +"|");
        //预约序号 Char/2 用户预约的就诊序号 否
        inData.append(record.getSerialNumber()+"|");
        //服务商编码 String(4) 否
        inData.append("py"+"|");
        //工号 String(50) 服务商操作人员工号或预约用户 IP 否
        inData.append("127.0.0.1"+"|");
        //预约机构代码 String(10) 是
        inData.append(hospital.getHosMarkCode()+"|");
        //预约机构名称 String(30) 机构名称如 12580、朝辉社区 是
        inData.append(hospital.getHosName()+"|");
        //平台时间 Date YYYY-MM-DD HH:MM:SS例：2017-01-12 08:12:43是
        inData.append(LocalDateTimeUtil.format(LocalDateTime.now(),"yyyy-MM-dd HH:mm:ss"));
        String tokenStr = "";
        try {
            System.out.println(inData.toString());
            tokenStr = HttpUtil.post(hospital.getHosRegionalCode()+"/book/storedProcedure", "inData="+inData.toString());
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("第三方接口异常");
        }
        HttpResult httpResult = JSONUtil.toBean(JSONUtil.parseObj(tokenStr),HttpResult.class);
        ExecutionResult executionResult = JSONUtil.toBean(JSONUtil.parseObj(httpResult.getData()),ExecutionResult.class);
        return executionResult;
    }



    /**
     * 取消HIS预约
     * @param record
     * @return
     * @throws Exception
     */
    private ExecutionResult deleteDataHIS(OrdAppointment record) throws Exception {
        StringBuilder inData =  new StringBuilder();
        PubHospital hospital = hospitalMapper.selectByPrimaryKey(record.getHospitalId());
        //取消HIS中的预约数据
        //20151122|69514581|3031307
        //就诊日期 Timestamp 格式：YYYYMMDD 否
        inData.append(LocalDateTimeUtil.format(record.getVisitDate(), DatePattern.PURE_DATE_PATTERN)+"|");
        //取号密码 String(8) 8 位的取号密码，一周内不可重复，可 0 否浙江省医院预约诊疗服务系统医院接入规范 第 30 页 开头，不可字母。
        inData.append(record.getPassword()+"|");
        //用户编号 String
        inData.append(record.getPatId().toString());
        String tokenStr = "";
        try {
            tokenStr = HttpUtil.post(hospital.getHosRegionalCode()+"/cancel/storedProcedure", "inData="+inData.toString());
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("第三方接口异常");
        }
        HttpResult httpResult = JSONUtil.toBean(JSONUtil.parseObj(tokenStr),HttpResult.class);
        ExecutionResult executionResult = JSONUtil.toBean(JSONUtil.parseObj(httpResult.getData()),ExecutionResult.class);
        return executionResult;
    }

}
